﻿using Common;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace AutoUpdateServer
{
    public delegate void VoidDelegate(Action action);

    public partial class AutoUpdateServer : Form
    {
        public AutoUpdateServer()
        {
            InitializeComponent();

            ValidationData();
        }

        private long TimeStamp = -1;
        private string CheckCode = string.Empty;
        private List<Common.FileInfo> FileInfos = new List<Common.FileInfo>();
        private string OutPutPath = string.Empty;
        private string SourcePath = string.Empty;

        const int CheckCodeLength = 64;

        private void RunInMainThread(Action action)
        {
            if (this.InvokeRequired)
                this.Invoke(new VoidDelegate(RunInMainThread), new[] { action });
            else
                action();
        }

        private void ValidationData()
        {
            bool success = false;

            while (true)
            {
                if (TimeStamp == -1)
                    break;

                if (string.IsNullOrEmpty(CheckCode))
                    break;

                if (FileInfos.Count == 0)
                    break;

                if (string.IsNullOrEmpty(OutPutPath))
                    break;

                success = true;
                break;
            }

            button_handle.Enabled = success;
        }

        private string GetCheckCode()
        {
            return TokenHelper.GetInstance().GetRandomToken(CheckCodeLength);
        }

        private long GetTimeStamp()
        {
            return (DateTime.Now.ToUniversalTime().Ticks - 621355968000000000) / 10000000;
        }

        private void AutoUpdateServer_Load(object sender, EventArgs e)
        {
            CheckCode = GetCheckCode();
            textBox_checkcode.Text = CheckCode;

            TimeStamp = GetTimeStamp();
            textBox_time_stamp.Text = TimeStamp.ToString();

            ValidationData();
        }

        private void button_reset_checkcode_Click(object sender, EventArgs e)
        {
            CheckCode = GetCheckCode();
            textBox_checkcode.Text = CheckCode;
            ValidationData();
        }

        private void SetFrozen(bool frozen)
        {
            var list = new[] { button_file, button_reset_checkcode, button_time_stamp, button_ouput };
            foreach (var item in list)
            {
                item.Enabled = !frozen;
            }
        }

        private void ShowSystemStatus(string status = null)
        {
            RunInMainThread(() => { label_status.Text = status; });
        }

        private void button_file_Click(object sender, EventArgs e)
        {
            FileInfos.Clear();

            var fbd = new FolderBrowserDialog();
            if (fbd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                SourcePath = fbd.SelectedPath;
                richTextBox1.Text = string.Empty;
                SetFrozen(true);
                new Thread(() =>
                {
                    ShowSystemStatus("正在获取文件");
                    var all_files = FileHelper.GetAllChildFilePath(SourcePath);
                    ShowSystemStatus();

                    foreach (var file in all_files)
                    {
                        try
                        {
                            var md5 = FileHelper.GetMd5(file);
                            RunInMainThread(() =>
                            {
                                richTextBox1.AppendText(file + "\r\n");
                                richTextBox1.AppendText(md5 + "\r\n\r\n");
                            });

                            FileInfos.Add(new Common.FileInfo
                            {
                                FileMD5 = md5,
                                FilePath = FileHelper.GetRelativePath(file, SourcePath),
                                FileUrl = string.Format("{0}_{1}", TokenHelper.GetInstance().GetRandomToken(6), md5)
                            });
                        }
                        catch (Exception ex)
                        {
                            RunInMainThread(() =>
                            {
                                richTextBox1.AppendText(ex.Message);
                            });
                        }
                    }

                    RunInMainThread(() => { SetFrozen(false); });
                    RunInMainThread(() => { ValidationData(); });
                }).Start();
            }
        }

        private void button_time_stamp_Click(object sender, EventArgs e)
        {
            TimeStamp = GetTimeStamp();
            textBox_time_stamp.Text = TimeStamp.ToString();
            ValidationData();
        }

        private void ShowStatus(string name, Action action)
        {
            RunInMainThread(() => { label_status.Text = name + "\tStart"; });
            action();
            RunInMainThread(() => { label_status.Text = name + "\tFinsh"; });
        }

        private void button_handle_Click(object sender, EventArgs e)
        {
            string ServerUrl = textBox_url.Text;
            string OtherInfo = textBox_other.Text;

            new Thread(() =>
            {
                RunInMainThread(() => { this.Enabled = false; });

                LitJson.JsonWriter writer = new LitJson.JsonWriter();

                writer.WriteObjectStart();

                writer.WritePropertyName("VersionsCheckCode");
                writer.Write(CheckCode);

                writer.WritePropertyName("TimeStamp");
                writer.Write(TimeStamp);

                if (!string.IsNullOrEmpty(ServerUrl))
                {
                    writer.WritePropertyName("ServerUrl");
                    writer.Write(ServerUrl);
                }

                if (!string.IsNullOrEmpty(OtherInfo))
                {
                    var other_items = OtherInfo.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
                    foreach (var other_item in other_items)
                    {
                        var items = other_item.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries);
                        if (items.Length >= 2)
                        {
                            writer.WritePropertyName(items[0]);
                            writer.Write(items[1]);
                        }
                    }
                }

                writer.WritePropertyName("FileInfos");
                writer.WriteArrayStart();


                var file_info_type = typeof(Common.FileInfo);
                var PropertyList = new[] { "FilePath", "FileMD5", "FileUrl" };

                int i = 0;
                foreach (var item in FileInfos)
                {
                    i++;
                    writer.WriteObjectStart();

                    foreach (var p_item in PropertyList)
                    {
                        var Property = file_info_type.GetProperty(p_item);
                        var value = Property.GetValue(item);

                        writer.WritePropertyName(p_item);
                        writer.Write(value.ToString());
                    }

                    writer.WriteObjectEnd();

                    RunInMainThread(() => { label_status.Text = string.Format("({0}/{1})", i, FileInfos.Count); });
                }

                writer.WriteArrayEnd();

                writer.WriteObjectEnd();

                string text = writer.ToString();

                FileHelper.RemoveAllChild(OutPutPath);
                var upload_path = Path.Combine(OutPutPath, "UpLoad");
                if (!Directory.Exists(upload_path))
                    Directory.CreateDirectory(upload_path);

                ShowStatus("Write VersionInfo.json", () =>
                {
                    StreamWriter sw = new StreamWriter(Path.Combine(OutPutPath, "VersionInfo.json"));
                    sw.Write(text);
                    sw.Close();
                });

                foreach (var item in FileInfos)
                {
                    ShowStatus("FileCopy" + item.FilePath, () =>
                    {
                        File.Copy(Path.Combine(SourcePath, item.FilePath), Path.Combine(OutPutPath, "UpLoad", item.FileUrl));
                    });
                }

                RunInMainThread(() => { label_status.Text = "All Finsh"; });
                RunInMainThread(() => { this.Enabled = true; });
            }).Start();
        }

        private void button_ouput_Click(object sender, EventArgs e)
        {
            var fbd = new FolderBrowserDialog();
            if (fbd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                OutPutPath = fbd.SelectedPath;
                textBox_output.Text = OutPutPath;
            }

            ValidationData();
        }
    }
}
